Skip to content

Support batching different queries together.#4342

Open
jgiles wants to merge 2 commits intosqlc-dev:mainfrom
paxosglobal:fr-4195-batch-different-queries
Open

Support batching different queries together.#4342
jgiles wants to merge 2 commits intosqlc-dev:mainfrom
paxosglobal:fr-4195-batch-different-queries

Conversation

@jgiles
Copy link

@jgiles jgiles commented Mar 15, 2026

Fix #4195 by adding an emit_query_batch codegen option that creates a QueryBatch type when using pgx v5.

When emit_query_batch: true is set in config (pgx/v5 only), sqlc generates:

  • A QueryBatch struct wrapping pgx.Batch
  • NewQueryBatch() constructor
  • Queue* methods for each query (:one, :many, :exec, :execrows, :execresult)
  • ExecuteBatch() on Queries to send all queued queries in one round-trip

This expands the batching support of existing :batchone/:batchmany/:batchexec annotations, which required separate query definitions and only supported baching the same query with different parameters. Batching multiple instances of the same query with different parameters is also supported via the new interface. While there is probably not a good reason to use both in the same package, you can generate and use both without error for backwards compatibility.

Key design decisions

  • Follows pgx v5's recommended QueuedQuery callback pattern
  • QueryBatch.Batch is exported so users can mix generated Queue* calls with custom pgx batch operations
  • :exec queries have no callback (consistent with pgx - errors propagate via Close/ExecuteBatch)
  • :one callbacks receive a bool indicating whether a row was found

Changes

  • internal/codegen/golang/gen.go - Wire up EmitQueryBatch option, file generation, and validation
  • internal/codegen/golang/imports.go - Add queryBatchImports() with import logic that skips struct field types (struct definitions live in query.sql.go, not the batch file). Extract queryUsesType() from inline closure for reuse.
  • internal/codegen/golang/opts/options.go - Add EmitQueryBatch and OutputQueryBatchFileName options
  • internal/codegen/golang/templates/pgx/queryBatchCode.tmpl - New template for all query batch methods
  • internal/codegen/golang/templates/template.tmpl - Add queryBatchFile and queryBatchCode template definitions

Test coverage

  • emit_query_batch - Full test with :one, :many, :exec, :execrows, :execresult
  • emit_query_batch_db_arg - With emit_methods_with_db_argument: true
  • emit_query_batch_minimal - Non-struct return types (verifies import handling for e.g. pgtype.Timestamptz)
  • emit_query_batch_overrides - With custom type overrides (verifies batch file doesn't import types only used in struct fields)
  • emit_query_batch_with_batch - Combines old-style :batchexec with emit_query_batch (verifies both batch.go and query_batch.sql.go coexist correctly)

Documentation

  • docs/reference/config.md - Added emit_query_batch and output_query_batch_file_name
  • docs/reference/query-annotations.md - New section with usage examples contrasting with :batch* annotations

Fix sqlc-dev#4195 by adding an emit_query_batch codegen option that creates a
QueryBatch type when using pgx v5.

When emit_query_batch: true is set in config (pgx/v5 only), sqlc generates:
- A QueryBatch struct wrapping pgx.Batch
- NewQueryBatch() constructor
- Queue* methods for each query (:one, :many, :exec, :execrows, :execresult)
- ExecuteBatch() on Queries to send all queued queries in one round-trip

This expands the batching support of existing :batchone/:batchmany/:batchexec annotations,
which required separate query definitions and only supported baching the
same query with different parameters. Batching multiple instances of the
same query with different parameters is also supported via the new
interface. While there is probably not a good reason to use both in the
same package, you can generate and use both without error for backwards
compatibility.

Key design decisions

- Follows pgx v5's recommended QueuedQuery callback pattern
- QueryBatch.Batch is exported so users can mix generated Queue* calls with custom pgx batch operations
- :exec queries have no callback (consistent with pgx - errors propagate via Close/ExecuteBatch)
- :one callbacks receive a bool indicating whether a row was found

Changes

- internal/codegen/golang/gen.go - Wire up EmitQueryBatch option, file generation, and validation
- internal/codegen/golang/imports.go - Add queryBatchImports() with import logic that skips struct field types (struct definitions live in query.sql.go, not the batch file). Extract queryUsesType() from inline
 closure for reuse.
- internal/codegen/golang/opts/options.go - Add EmitQueryBatch and OutputQueryBatchFileName options
- internal/codegen/golang/templates/pgx/queryBatchCode.tmpl - New template for all query batch methods
- internal/codegen/golang/templates/template.tmpl - Add queryBatchFile and queryBatchCode template definitions

Test coverage

- emit_query_batch - Full test with :one, :many, :exec, :execrows, :execresult
- emit_query_batch_db_arg - With emit_methods_with_db_argument: true
- emit_query_batch_minimal - Non-struct return types (verifies import handling for e.g. pgtype.Timestamptz)
- emit_query_batch_overrides - With custom type overrides (verifies batch file doesn't import types only used in struct fields)
- emit_query_batch_with_batch - Combines old-style :batchexec with emit_query_batch (verifies both batch.go and query_batch.sql.go coexist correctly)

Documentation

- docs/reference/config.md - Added emit_query_batch and output_query_batch_file_name
- docs/reference/query-annotations.md - New section with usage examples contrasting with :batch* annotations
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Mar 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FR: Support batching different queries together

1 participant